/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package ucmconfchecker;

import java.awt.Dimension;
import java.awt.Point;
import java.awt.Shape;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import org.apache.xmlbeans.XmlException;
import org.isistan.flabot.coremodelEcore.*;
import org.isistan.flabot.edit.editormodelEcore.Diagram;
import org.isistan.flabot.edit.editormodelEcore.FlabotFileModel;
import org.isistan.flabot.edit.editormodelEcore.FlabotFileModelDocument;
import org.isistan.flabot.edit.editormodelEcore.VisualModel;
import ucmconfchecker.pArchitecture.Architecture;
import ucmconfchecker.pArchitecture.Component;
import ucmconfchecker.pArchitecture.Responsibility;
import ucmconfchecker.pUCM.*;
import ucmconfchecker.ucmrender.UCMFlabotLayout;

/**
 *
 * @author Administrador
 */
public class FlabotHandler {
    String pathFlabot;
    FlabotFileModel flabot;
    
    //indexa los componentes y responsabilidades, para que no existen multiples
    //instancias de cada uno; de esta forma, los distintos los diagramas comparten.
    HashMap<Integer,Responsibility> responsibilities = new HashMap<Integer,Responsibility>();
    HashMap<Integer,Component> components = new HashMap<Integer,Component>();
    
    public FlabotHandler(String pathFlabot){
        this.pathFlabot = pathFlabot;
        FlabotFileModelDocument flabotDoc =null;
        try
          {
              flabotDoc = FlabotFileModelDocument.Factory.parse(new File(pathFlabot));
          } catch (XmlException e)
          {
              e.printStackTrace();
          }catch (IOException e)
          {
              e.printStackTrace();
          }
          flabot = flabotDoc.getFlabotFileModel();          
    }
    private Responsibility getResponsibility(int id){
        Responsibility responsibility = responsibilities.get(id);
        if(responsibility==null){
            responsibility = new Responsibility(getComponent(flabot.getCoreModelArray(0).getResponsibilitiesArray(id).getComponents2()),
                                                flabot.getCoreModelArray(0).getResponsibilitiesArray(id).getName());
            responsibilities.put(id,responsibility);
        }
        return responsibility;
    }
    private Component getComponent(int id) {
        Component component = components.get(id);
        if(component==null){
            component =new Component(flabot.getCoreModelArray(0).getComponentsArray(id).getName());
            components.put(id, component);
        }
        return component;
                    
    }
    public Responsibility getResponsibility(String direction) {
        
        String[] tokens = direction.replace("/", "\\").split("\\\\")[3].split("\\.");
        int id = Integer.parseInt(tokens[1]);
        //return flabot.getCoreModelArray(0).getResponsibilitiesArray(id).getName();
        return  getResponsibility(id);
    }
    public Component getComponent(String direction) {
        String[] tokens = direction.replace("/", "\\").split("\\\\")[3].split("\\.");
        int id = Integer.parseInt(tokens[1]);
        return getComponent(id);
    }
    public Architecture<Responsibility,Component> getArchitecture(){
        ArrayList<Component> archComponents = new ArrayList<Component>();
        for(int comp = 0; comp<flabot.getCoreModelArray(0).getComponentsArray().length;comp++)
            archComponents.add(getComponent(comp));
        ArrayList<Responsibility> archResponsibilities = new ArrayList<Responsibility>();
        for(int resp = 0; resp<flabot.getCoreModelArray(0).getResponsibilitiesArray().length;resp++)
            archResponsibilities.add(getResponsibility(resp));
        return new Architecture<Responsibility,Component>(archComponents, archResponsibilities);
    }
    public int getUCMCount(){
        if(flabot.getCoreModelArray()!=null)
            return flabot.getCoreModelArray().length;
        else
            return 0;
    }
    public UCM getUCM(int id){
        UseCaseMap ucm = flabot.getCoreModelArray(0).getUseCaseMapsArray(id);
        ComponentRole roles[] = ucm.getComponentRolesArray();
        ArrayList<ComponentInstance> instances = new ArrayList<ComponentInstance>();
        for(int r=0; r<roles.length;r++){
            instances.add(new ComponentInstance(getComponent(roles[r].getComponent2())));
        }
        HashMap<Integer,ArrayList<UCMNode>> globalNodeList = new HashMap<Integer,ArrayList<UCMNode>>();
        ArrayList<UCMNode> starts = new ArrayList<UCMNode>();
        HashMap<UCMNode, ArrayList<UCMNode>> arcs = new HashMap<UCMNode, ArrayList<UCMNode>>();
        HashMap<UCMNode, ArrayList<UCMNode>> preconditions = new HashMap<UCMNode, ArrayList<UCMNode>>();
        Path[] paths = ucm.getPathsArray();
        for(int p =0; p<paths.length;p++){
            Path path = paths[p];
            PathNode[] nodes =path.getNodesArray();
            System.out.println("Nodes:");
            ArrayList<UCMNode> nodeList = new ArrayList<UCMNode>();
            for(int n =0; n<nodes.length;n++){
               //parseo manual del tipo, porque el metodo .getType() no anda
               String type  = nodes[n].toString().split("\\\"")[1];
               if(type.equals("org.isistan.flabot.coremodel:SimplePathNode")){
                   if(getId(path.getStartNodes2())==n){
                       UCMStart start = new UCMStart();
                       nodeList.add(start);
                       starts.add(start);
                   }else if(getId(path.getEndNodes2())==n){
                       nodeList.add(new UCMEnd());
                   }else
                       throw new UnsupportedOperationException("Invalid Node");
                   
               }else if(type.equals("org.isistan.flabot.coremodel:ResponsibilityNode")){
                   UCMResponsibility responsibility = new UCMResponsibility(instances.get(getId(((ResponsibilityNode)nodes[n]).getRole2())),
                                                                            getResponsibility(((ResponsibilityNode)nodes[n]).getResponsibility2()));
                   nodeList.add(responsibility);
               }else{
                   //captura de los otros tipos de nodos
               }
                System.out.println(" "+n+"."+nodeList.get(nodeList.size()-1));
            }
            globalNodeList.put(p,nodeList);
            
            String currentPath =path.getStartNodes2(); 
            while(currentPath!=null){
                int currentId = getId(currentPath);
                String nextPath = nodes[currentId].getNext2();
                UCMNode currentNode = nodeList.get(currentId);
                System.out.println(""+currentId+"."+currentNode);
                if(nextPath!=null){
                    int nextId = getId(nextPath);
                    ArrayList<UCMNode> currentArcs = arcs.get(currentNode);
                    if(currentArcs==null){
                        currentArcs = new ArrayList<UCMNode>();
                        arcs.put(currentNode, currentArcs);
                    }
                    currentArcs.add(nodeList.get(nextId));    
                }        
                currentPath = nextPath;
            }
            System.out.println("");
           
        }
        org.isistan.flabot.coremodelEcore.Responsibility[] responsibilityArray= flabot.getCoreModelArray(0).getResponsibilitiesArray();
        for(int responsibilityId =0; responsibilityId<responsibilityArray.length; responsibilityId++){
            Condition[] precs = responsibilityArray[responsibilityId].getPreconditionsArray();
            for (int pre=0; pre<precs.length;pre++) {
//                System.out.println("++PRECONDITION: "+precs[pre]);
                if(getId(precs[pre].getUseCaseMap2())==id){
                      String sourcePath = precs[pre].getSourceResponsibility2();
                      UCMNode source = globalNodeList.get(getGroup(sourcePath)).get(getId(sourcePath));
                      System.out.println("sources;"+ source);
//
                    String dependencyPath = precs[pre].getDependencyResponsibility2();//depende de esta
                    
                    UCMNode dependency = globalNodeList.get(getGroup(dependencyPath)).get(getId(dependencyPath));
                    System.out.println("dep;"+ getGroup(dependencyPath)+" "+getId(dependencyPath)+": "+dependency);
//
                    ArrayList<UCMNode> currentPrecs = preconditions.get(dependency);
                    if(currentPrecs==null){
                        currentPrecs = new ArrayList<UCMNode>();
                        preconditions.put(dependency,currentPrecs);
                    }
                    currentPrecs.add(source);
                }
            }
        }
        ArrayList<UCMNode> nodeList = new ArrayList<UCMNode>();
        for(Integer path: globalNodeList.keySet())
            nodeList.addAll(globalNodeList.get(path));
        
        
        Diagram diagram = null;
        Diagram[] diagrams = flabot.getDiagramsArray();
        int realId = -1;
        for(int diagramId = 0; diagramId<diagrams.length;diagramId++){
            Diagram currentDiagram = flabot.getDiagramsArray(diagramId);
            String type = currentDiagram.toString().split("\\\"")[1];
            if(type.equals("org.isistan.flabot.edit.ucmmodel:UCMDiagram")){
                realId++;
            }
            if(realId == id){
                diagram = currentDiagram;
            }
        }
//        System.out.println("DIAGRAM: " +diagram.xmlText());
        UCMFlabotLayout layout = new UCMFlabotLayout();
        int width =0;
        int height = 0;
        if(diagram!=null){
            for(VisualModel componentVisualModel: diagram.getChildrenArray()){
    //            System.out.println("COMPONENT: " +componentVisualModel.xmlText());
                int componentX = componentVisualModel.getLocationArray(0).getX();
                if(componentX<0){componentX=0;}   
                int componentY = componentVisualModel.getLocationArray(0).getY();
                if(componentY<0){componentY=0;}
                int componentWidth =  componentVisualModel.getSizeArray(0).getWidth();
                width = Math.max(width,componentX+componentWidth);
                int componentHeight =  componentVisualModel.getSizeArray(0).getHeight();
                height = Math.max(height,componentY+componentHeight);
                String componentPath = componentVisualModel.getSemanticModel2();
//                System.out.println("comp: "+componentPath);
                String component = flabot.getCoreModelArray(0).getUseCaseMapsArray(id).getComponentRolesArray(getId(componentPath)).getComponent2();
                if(componentVisualModel.getChildrenArray().length>0){
                    System.out.println("COMPONENT: " +(componentX)+","+(componentY)+":: "+getComponent(getId(component)));
                    layout.setLocation(getComponent(getId(component)), new Point(componentX,componentY));
                    layout.setDimensions(getComponent(getId(component)), new Dimension(componentWidth,componentHeight));
                    for(VisualModel activationVisualModel: componentVisualModel.getChildrenArray()){
                        int activationX = activationVisualModel.getLocationArray(0).getX();
                        if(activationX<0){activationX=0;}
                        int activationY = activationVisualModel.getLocationArray(0).getY();
                        if(activationY<0){activationY=0;}
                        String responsibilityPath = activationVisualModel.getSemanticModel2();
    //                    System.out.println("Path:" +responsibilityPath);
                        int respGroup = getGroup(responsibilityPath);
                        int respId = getId(responsibilityPath);
                        UCMResponsibility responsibility = (UCMResponsibility) globalNodeList.get(respGroup).get(respId);
                        System.out.println("RESPONSIBILITY: " +(activationX)+","+(activationY)+":: "+responsibility);
                        layout.setLocation(responsibility.getResponsibility(), new Point(componentX+activationX,componentY+activationY));
                    }
                }
            }
            layout.setSize(new Dimension(width,height));
        }
        UCM result = new UCM(instances,nodeList, arcs, preconditions,starts);
        result.setLayout(layout);
        return result;
    }
    
    private int getId(String path){
        String[] tokens = path.split("\\.");
        return Integer.parseInt(tokens[tokens.length-1]);
    }
    private int getGroup(String path){
        String[] tokens = path.split("[\\\\/]");
        return Integer.parseInt(tokens[tokens.length-2].split("\\.")[1]);
    }
}

